package com.ziyueyuwen.xiniao.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.suyeer.basic.util.JsonUtil;
import com.ziyueyuwen.xiniao.bean.homework.*;
import com.ziyueyuwen.xiniao.bean.vo.ZyCourseVO;
import com.ziyueyuwen.xiniao.bean.vo.ZyQuestionDataVO;
import com.ziyueyuwen.xiniao.dao.ZyCourseInfoMapper;
import com.ziyueyuwen.xiniao.dao.ZyQuestionDataMapper;
import com.ziyueyuwen.xiniao.dao.ZySubjectMapper;
import com.ziyueyuwen.xiniao.dao.ZySubjectQuestionMapper;
import com.ziyueyuwen.xiniao.enums.LessonModuleEnum;
import com.ziyueyuwen.xiniao.enums.QuestionTypeEnum;
import com.ziyueyuwen.xiniao.service.SubjectQuestionService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author jun 2018/12/20.
 */
@Service
public class SubjectQuestionServiceImpl implements SubjectQuestionService {

    @Autowired
    private ZyCourseInfoMapper zyCourseInfoMapper;

    @Autowired
    private ZySubjectQuestionMapper zySubjectQuestionMapper;

    @Autowired
    private ZySubjectMapper zySubjectMapper;

    @Autowired
    private ZyQuestionDataMapper zyQuestionDataMapper;

    @Override
    public Boolean add(ZySubjectQuestionDO zySubjectQuestionDO) {
        return zySubjectQuestionMapper.add(zySubjectQuestionDO);
    }

    @Override
    public List<ZySubjectQuestionDO> listBySubjectId(Integer subjectId) {
        return zySubjectQuestionMapper.listBySubjectId(subjectId);
    }

    @Override
    public ZySubjectQuestionDO getById(Integer id) {
        return zySubjectQuestionMapper.getById(id);
    }

    @Override
    public ZySubjectQuestionDO getBySubjectIdAndHomeworkIndex(Integer subjectId, Integer homeworkIndex) {
        return zySubjectQuestionMapper.getBySubjectIdAndHomeworkIndex(subjectId, homeworkIndex);
    }

    @Override
    public HashMap<Integer, SubjectQuestionExistElementData> getSubjectQuestionExistElementDataInfoBySubjectId(Integer subjectId) {
        List<ZySubjectQuestionDO> zySubjectQuestionList = zySubjectQuestionMapper.listBySubjectId(subjectId);
        HashMap<Integer, SubjectQuestionExistElementData> retMap = new HashMap<>(8);
        for (ZySubjectQuestionDO zySubjectQuestion : zySubjectQuestionList) {
            SubjectQuestionExistElementData existElementData = new SubjectQuestionExistElementData();
            existElementData.setIfHaveExpandInfo(!CollectionUtils.isEmpty(zySubjectQuestion.getExpandInfoList()));
            existElementData.setIfHavePreviewInfo(!CollectionUtils.isEmpty(zySubjectQuestion.getPreviewInfoList()));
            existElementData.setIfHaveQuestionInfo(!CollectionUtils.isEmpty(zySubjectQuestion.getQuestionInfoList()));
            existElementData.setIfHaveSummaryInfo(!CollectionUtils.isEmpty(zySubjectQuestion.getSummaryInfoList()));
            retMap.put(zySubjectQuestion.getHomeworkIndex(), existElementData);
        }
        return retMap;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveSubjectQuestion(Integer courseId, Integer lessonIndex, String answerOrder) throws Exception {
        ZySubjectQuestionDO zySubjectQuestion = getZySubjectQuestionDO(courseId, lessonIndex);
        if (StringUtils.isNotBlank(answerOrder)) {
            JSONObject obj = JSON.parseObject(answerOrder);
            if (obj.containsKey("limitTime")) {
                zySubjectQuestion.getAnswerOrder().put("limitTime", obj.getInteger("limitTime"));
            }
            if (obj.containsKey("classroomTestLimitTimeList")) {
                if (!zySubjectQuestion.getAnswerOrder().containsKey("classroomTestLimitTimeList")) {
                    zySubjectQuestion.getAnswerOrder().put("classroomTestLimitTimeList", new JSONObject());
                }
                zySubjectQuestion.getAnswerOrder().getJSONObject("classroomTestLimitTimeList").putAll(obj.getJSONObject("classroomTestLimitTimeList"));
            }
        }
        zySubjectQuestion.getQuestionInfoList().clear();
        zySubjectQuestion.getClassroomTestInfoList().clear();

        setData(courseId, lessonIndex, LessonModuleEnum.PREVIEW, zySubjectQuestion.getPreviewInfoList());
        setData(courseId, lessonIndex, LessonModuleEnum.SUMMARY, zySubjectQuestion.getSummaryInfoList());
        setData(courseId, lessonIndex, LessonModuleEnum.EXPAND, zySubjectQuestion.getExpandInfoList());

        List<ZyQuestionDataVO> homeworkDataList = zyQuestionDataMapper.getQuestionDataOfCourseLesson(courseId, lessonIndex, LessonModuleEnum.HOMEWORK, null);
        for (ZyQuestionDataVO zyQuestionData : homeworkDataList) {
            QuestionInfo questionInfo = createQuestionInfo(zyQuestionData.getQuestionDataObject());
            zySubjectQuestion.getQuestionInfoList().add(questionInfo);
        }

        List<ZyQuestionDataVO> classroomTestDataList = zyQuestionDataMapper.getQuestionDataOfCourseLesson(courseId, lessonIndex, LessonModuleEnum.CLASSROOM_TEST, null);
        for (ZyQuestionDataVO zyQuestionData : classroomTestDataList) {
            QuestionInfo questionInfo = createQuestionInfo(zyQuestionData.getQuestionDataObject());
            zySubjectQuestion.getClassroomTestInfoList().add(questionInfo);
        }
        zySubjectQuestionMapper.update(zySubjectQuestion);
    }

    private ZySubjectQuestionDO getZySubjectQuestionDO(Integer courseId, Integer lessonIndex) throws Exception {
        Integer subjectId = getSubjectId(courseId);
        ZySubjectQuestionDO zySubjectQuestion = zySubjectQuestionMapper.getBySubjectIdAndHomeworkIndex(subjectId, lessonIndex);
        if (zySubjectQuestion == null) {
            zySubjectQuestion = new ZySubjectQuestionDO();
            zySubjectQuestion.setSubjectId(subjectId);
            zySubjectQuestion.setHomeworkIndex(lessonIndex);
            synchronized (this) {
                ZySubjectQuestionDO tmp = zySubjectQuestionMapper.getBySubjectIdAndHomeworkIndex(subjectId, lessonIndex);
                if (tmp == null) {
                    zySubjectQuestionMapper.add(zySubjectQuestion);
                } else {
                    zySubjectQuestion = tmp;
                }
            }
        }
        return zySubjectQuestion;
    }

    @Override
    public JSONObject getAnswerOrder(Integer courseId, Integer lessonIndex) throws Exception {
        ZySubjectQuestionDO zySubjectQuestion = getZySubjectQuestionDO(courseId, lessonIndex);
        return zySubjectQuestion.getAnswerOrder();
    }

    @Override
    public List<String> listMould(Integer courseId, Integer lessonIndex) throws Exception {
        ZySubjectQuestionDO zySubjectQuestion = getZySubjectQuestionDO(courseId, lessonIndex);
        JSONObject remarkInfo = zySubjectQuestion.getRemarkInfo();
        if (remarkInfo != null && remarkInfo.containsKey("mouldList")) {
            return JSON.parseArray(remarkInfo.getString("mouldList"), String.class);
        }
        return new ArrayList<>();
    }

    @Override
    public List<String> listTag(Integer courseId, Integer lessonIndex) throws Exception {
        ZySubjectQuestionDO zySubjectQuestion = getZySubjectQuestionDO(courseId, lessonIndex);
        JSONObject remarkInfo = zySubjectQuestion.getRemarkInfo();
        if (remarkInfo != null && remarkInfo.containsKey("tagList")) {
            return JSON.parseArray(remarkInfo.getString("tagList"), String.class);
        }
        return new ArrayList<>();
    }

    @Override
    public List<Integer> listClassroomTestLimitTime(Integer courseId, Integer lessonIndex) throws Exception {
        ZySubjectQuestionDO zySubjectQuestion = getZySubjectQuestionDO(courseId, lessonIndex);
        JSONObject answerOrder = zySubjectQuestion.getAnswerOrder();
        TreeMap<Integer, Integer> retMap = new TreeMap<>();
        for (int i = 1; i < 11; i++) {
            retMap.put(i, 0);
        }
        if (answerOrder.containsKey("classroomTestLimitTimeList")) {
            String str = answerOrder.getString("classroomTestLimitTimeList");
            TreeMap<Integer, Integer> treeMap = JSON.parseObject(str, new TypeReference<TreeMap<Integer, Integer>>() {
            }.getType());
            retMap.putAll(treeMap);
        }
        return new ArrayList<>(retMap.values());
    }

    @Override
    public void saveMouldList(Integer courseId, Integer lessonIndex, List<String> mouldList) throws Exception {
        ZySubjectQuestionDO zySubjectQuestion = getZySubjectQuestionDO(courseId, lessonIndex);
        zySubjectQuestion.getRemarkInfo().put("mouldList", mouldList);
        zySubjectQuestionMapper.update(zySubjectQuestion);
    }

    @Override
    public void saveTagList(Integer courseId, Integer lessonIndex, List<String> tagList) throws Exception {
        ZySubjectQuestionDO zySubjectQuestion = getZySubjectQuestionDO(courseId, lessonIndex);
        zySubjectQuestion.getRemarkInfo().put("tagList", tagList);
        zySubjectQuestionMapper.update(zySubjectQuestion);
    }

    @Override
    public String getPointGist(Integer courseId, Integer lessonIndex) throws Exception {
        ZySubjectQuestionDO zySubjectQuestion = getZySubjectQuestionDO(courseId, lessonIndex);
        JSONObject remarkInfo = zySubjectQuestion.getRemarkInfo();
        if (remarkInfo != null && remarkInfo.containsKey("pointGist")) {
            return remarkInfo.getString("pointGist");
        }
        return StringUtils.EMPTY;
    }

    @Override
    public void savePointGist(Integer courseId, Integer lessonIndex, String pointGist) throws Exception {
        ZySubjectQuestionDO zySubjectQuestion = getZySubjectQuestionDO(courseId, lessonIndex);
        zySubjectQuestion.getRemarkInfo().put("pointGist", pointGist);
        zySubjectQuestionMapper.update(zySubjectQuestion);
    }

    @Override
    public JSONObject getClassroomTestQuestion(Integer eeoClassId) throws Exception {
        IdInfoData idInfoData = zySubjectQuestionMapper.getIdInfoByEeoClassId(eeoClassId);
        ZySubjectQuestionDO zySubjectQuestion = getZySubjectQuestionDO(idInfoData.getCourseId(), idInfoData.getLessonIndex());
        JSONObject answerOrder = zySubjectQuestion.getAnswerOrder();
        JSONObject limitTimeObj = answerOrder.getJSONObject("classroomTestLimitTimeList");
        List<QuestionInfo> list = zySubjectQuestion.getClassroomTestInfoList();
        JSONObject retObj = new JSONObject();
        for (QuestionInfo q : list) {
            String idx = q.getClassroomTestIdx().toString();
            if (!retObj.containsKey(idx)) {
                retObj.put(idx, new JSONObject());
                retObj.getJSONObject(idx).put("questionList", new JSONArray());
            }
            retObj.getJSONObject(idx).put("limitTime", limitTimeObj.containsKey(idx) ? limitTimeObj.getInteger(idx) : 0);
            retObj.getJSONObject(idx).getJSONArray("questionList").add(q);
        }
        return retObj;
    }

    private QuestionInfo createQuestionInfo(JSONObject qObj) {
        JSONArray scoreArr = qObj.getJSONArray("scoreMap");
        JSONArray optionArr = qObj.getJSONArray("optionMap");
        JSONArray groupList = qObj.getJSONArray("groupList");
        qObj.remove("scoreMap");
        qObj.remove("optionMap");
        qObj.remove("groupList");
        QuestionInfo questionInfo = JsonUtil.changeType(qObj, QuestionInfo.class);
        TreeMap<String, Integer> scoreMap = new TreeMap<>();
        char scoreMapKeyIndex = '1';
        char optionMapKeyIndex = 'A';
        if (questionInfo.getQuestionType() == QuestionTypeEnum.CHOICE || questionInfo.getQuestionType() == QuestionTypeEnum.JUDGE) {
            scoreMapKeyIndex = 'A';
        }
        if (scoreArr != null) {
            for (int i = 0; i < scoreArr.size(); i++) {
                scoreMap.put(String.valueOf((char) (scoreMapKeyIndex + i)), scoreArr.getIntValue(i));
            }
            questionInfo.setScoreMap(scoreMap);
        }

        // 判断题 单选题和多选题有option选项, 需要处理; 答案是数字, 需要转成字母
        if (optionArr != null) {
            TreeMap<String, List<ItemData>> optionMap = new TreeMap<>();
            for (int i = 0; i < optionArr.size(); i++) {
                ItemData itemData = optionArr.getObject(i, ItemData.class);
                List<ItemData> itemDataList = new ArrayList<>();
                itemDataList.add(itemData);
                optionMap.put(String.valueOf((char) (optionMapKeyIndex + i)), itemDataList);
            }
            questionInfo.setOptionMap(optionMap);
            List<String> answerList = questionInfo.getAnswerList();
            for (int i = 0; i < answerList.size(); i++) {
                answerList.set(i, String.valueOf((char) (optionMapKeyIndex + Integer.valueOf(answerList.get(i)) - 1)));
            }
        }

        // 连线题需要将题目右侧的数据乱序, 答案也随机生成
        if (questionInfo.getQuestionType() == QuestionTypeEnum.CONNECTION_PROBLEM) {
            List<String> rightDataList = questionInfo.getRightDataList();
            List<String> tempList = new ArrayList<>(rightDataList);
            Collections.shuffle(rightDataList);
            List<String> answerList = tempList.stream().map(s -> String.valueOf(rightDataList.indexOf(s) + 1)).collect(Collectors.toList());
            questionInfo.setAnswerList(answerList);
        }

        // 新连线题需要将题目右侧的数据乱序, 答案也随机生成
        if (questionInfo.getQuestionType() == QuestionTypeEnum.CONNECTION_PROBLEM_2) {
            List<ItemData> rightDataList = questionInfo.getNewRightDataList();
            Collections.shuffle(rightDataList);
            List<String> answerList = rightDataList.stream().map(i -> i.getLeft().toString()).collect(Collectors.toList());
            questionInfo.setAnswerList(answerList);
        }

        // 拖拽题
        if (questionInfo.getQuestionType() == QuestionTypeEnum.FILL_DRAG) {
            List<String> answerList = new ArrayList<>();
            List<ItemData> dragList = questionInfo.getDragDataList();
            int idx = 1;
            for (ItemData item : dragList) {
                if (item.getScore() > 0) {
                    item.setIdx(idx++);
                    answerList.add(StringUtils.EMPTY);
                }
            }
            Collections.shuffle(dragList);
            for (int i = 0; i < dragList.size(); i++) {
                ItemData itemData = dragList.get(i);
                if (itemData.getScore() > 0) {
                    answerList.set(itemData.getIdx() - 1, String.valueOf(i + 1));
                }
            }
            questionInfo.setAnswerList(answerList);
        }

        // 组合题
        if (questionInfo.getQuestionType() == QuestionTypeEnum.GROUP) {
            questionInfo.setGroupList(new ArrayList<>());
            for (int i = 0; i < groupList.size(); i++) {
                JSONObject item = groupList.getJSONObject(i);
                questionInfo.getGroupList().add(createQuestionInfo(item));
            }
        }
        return questionInfo;
    }

    private void setData(Integer courseId, Integer lessonIndex, LessonModuleEnum lessonModule, List<ItemData> itemDataList) {
        itemDataList.clear();
        List<ZyQuestionDataVO> expandDataList = zyQuestionDataMapper.getQuestionDataOfCourseLesson(courseId, lessonIndex, lessonModule, null);
        for (ZyQuestionDataVO zyQuestionData : expandDataList) {
            itemDataList.addAll(JSON.parseArray(zyQuestionData.getQuestionDataObject().getString("info"), ItemData.class));
        }
    }

    private Integer getSubjectId(Integer courseId) throws Exception {
        ZyCourseVO zyCourse = zyCourseInfoMapper.getByCourseId(courseId);
        if (zyCourse == null) {
            throw new Exception("课程不存在");
        }
        if (zyCourse.getSubjectId() == null) {
            ZySubjectDO zySubject = new ZySubjectDO();
            zySubject.setSubjectName(zyCourse.getCourseName());
            zySubjectMapper.add(zySubject);
            zyCourse.setSubjectId(zySubject.getId());
            zyCourseInfoMapper.updateByPrimaryKeySelective(zyCourse);
        }
        return zyCourse.getSubjectId();
    }
}
